{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit DesignerPrefs;

interface

uses Classes, SysUtils, FormPosition, AHMTypes, Logging, XMLHelper;

const
  PREFS_FILENAME = 'DesignerPreferences.xml';

  // Default values for preferences
  DEF_WINDOWS_SAVER = True;
  DEF_MEDIATE_SAVER = False;
  DEF_LARGE_TOOLBAR = True;
  DEF_THEME_NAME = '';
  DEF_SAVE_FORM_POS = True;
  DEF_MAIN_FORM_WIDTH = 800;
  DEF_MAIN_FORM_HEIGHT = 600;
  DEF_MAIN_FORM_MAXD = True;
  DEF_MAIN_FORM_VSPLIT = 250;
  DEF_MAIN_FORM_HSPLIT = 200;
  DEF_PREVENT_STRETCH = False;
  DEF_HORIZONTAL_LAYOUT = False;


type
  TAHMDesignerPrefsManager = class
  private
    FConfigPath: String;
    FWindowsSaver: Boolean;
    FMediateSaver: Boolean;
    FLargeMainToolbar: Boolean;
    FLargePreviewToolbar: Boolean;
    FPreventStretch: Boolean;
    FHorizLayout: Boolean;
    FThemeName: String;
    FSaveFormPos: Boolean;
    FMainFormState: TAHMFormState;
    FHelper: TAHMXMLHelper;
  protected
    procedure ReadFormState(State: TAHMFormState);
    procedure ReadMainFormState(State: TAHMFormState);
    function WriteFormState(State: TAHMFormState): String;
    function WriteMainFormState(State: TAHMFormState): String;
    function ParseXML(const Filepath: String): Boolean;
    procedure LogParsingError(const sErrorCode: String);
  public
    constructor Create;
    destructor Destroy; override;
    property WindowsScreenSaver: Boolean read FWindowsSaver write FWindowsSaver;
    property MediateScreenSaver: Boolean read FMediateSaver write FMediateSaver;
    property LargeMainToolbar: Boolean read FLargeMainToolbar write FLargeMainToolbar;
    property AutoOpenThemeName: String read FThemeName write FThemeName;
    property LargePreviewToolbar: Boolean read FLargePreviewToolbar write FLargePreviewToolbar;
    property PreventPreviewStretch: Boolean read FPreventStretch write FPreventStretch;
    property HorizontalLayout: Boolean read FHorizLayout write FHorizLayout;
    property SaveFormPosition: Boolean read FSaveFormPos write FSaveFormPos;
    property MainFormState: TAHMFormState read FMainFormState;
    procedure ResetDefaultPreferences;
    procedure LoadPreferences;
    procedure SavePreferences;
    procedure SaveAsXML(Lines: TStrings);
  end;

implementation

uses TagNames, XMLTags, ErrorCodes, ApplicationManager;


constructor TAHMDesignerPrefsManager.Create;
begin
  inherited;

  // Create state object for main form properties
  FMainFormState := TAHMFormState.Create;
  FMainFormState.AddProperty('pnLeftPanel', 'Width');
  FMainFormState.AddProperty('pnDescriptorList', 'Height');
  FMainFormState.AddProperty('pnDescriptorList', 'Width');

  // Cache config path as app manager will be free'd before we save
  FConfigPath := ApplicationManagerInstance.ConfigPath;

  // Initialise default preference values
  ResetDefaultPreferences;
end;

destructor TAHMDesignerPrefsManager.Destroy;
begin
  FMainFormState.Free;

  inherited;
end;

procedure TAHMDesignerPrefsManager.ResetDefaultPreferences;
begin
  // Set default values for preferences
  FWindowsSaver := DEF_WINDOWS_SAVER;
  FMediateSaver := DEF_MEDIATE_SAVER;
  FLargeMainToolbar := DEF_LARGE_TOOLBAR;
  FLargePreviewToolbar := DEF_LARGE_TOOLBAR;
  FThemeName := DEF_THEME_NAME;
  FSaveFormPos := DEF_SAVE_FORM_POS;
  FPreventStretch := DEF_PREVENT_STRETCH;
  FHorizLayout := DEF_HORIZONTAL_LAYOUT;

  // Set default form sizes
  with FMainFormState do
  begin
    PreviousPosition.Width := DEF_MAIN_FORM_WIDTH;
    PreviousPosition.Height := DEF_MAIN_FORM_HEIGHT;
    PreviousPosition.Maximized := DEF_MAIN_FORM_MAXD;
    GetProperty('pnLeftPanel', 'Width').PreviousValue := DEF_MAIN_FORM_VSPLIT;
    GetProperty('pnDescriptorList', 'Height').PreviousValue := DEF_MAIN_FORM_HSPLIT;
    GetProperty('pnDescriptorList', 'Width').PreviousValue := DEF_MAIN_FORM_HSPLIT;
  end;
end;

procedure TAHMDesignerPrefsManager.LoadPreferences;
var
  Prefs: TStringList;
begin
  // First set default values for prefs
  ResetDefaultPreferences;

  // Parse XML to populate custom preference values
  ParseXML(FConfigPath);

  // Log our preference settings for support purposes
  Prefs := TStringList.Create;
  try
    Prefs.Add('mediate designer preference settings are as follows:');
    SaveAsXML(Prefs);
    LogInfo(Prefs);
  finally
    Prefs.Free;
  end;
end;

procedure TAHMDesignerPrefsManager.SavePreferences;
var
  Prefs: TStringList;
begin
  Prefs := TStringList.Create;
  try
    SaveAsXML(Prefs);
    Prefs.SaveToFile(FConfigPath + PREFS_FILENAME);
  finally
    Prefs.Free;
  end;
end;

procedure TAHMDesignerPrefsManager.ReadFormState(State: TAHMFormState);
begin
  with State.PreviousPosition do
  begin
    // Read position attributes to populate form state
    Top := StrToIntDef(FHelper.GetAttribute(ATTR_TOP), 0);
    Left := StrToIntDef(FHelper.GetAttribute(ATTR_LEFT), 0);
    Width := StrToIntDef(FHelper.GetAttribute(ATTR_WIDTH), 0);
    Height := StrToIntDef(FHelper.GetAttribute(ATTR_HEIGHT), 0);
    Maximized := Str2Bool(FHelper.GetAttribute(ATTR_MAXIMIZED));
  end;
end;

procedure TAHMDesignerPrefsManager.ReadMainFormState(State: TAHMFormState);
begin
  // Read standard form properties
  ReadFormState(State);

  State.GetProperty('pnLeftPanel', 'Width').PreviousValue :=
    StrToIntDef(FHelper.GetAttribute(ATTR_VSPLIT), DEF_MAIN_FORM_VSPLIT);
  if FHorizLayout then
    State.GetProperty('pnDescriptorList', 'Width').PreviousValue :=
      StrToIntDef(FHelper.GetAttribute(ATTR_HSPLIT), DEF_MAIN_FORM_HSPLIT)
  else
    State.GetProperty('pnDescriptorList', 'Height').PreviousValue :=
      StrToIntDef(FHelper.GetAttribute(ATTR_HSPLIT), DEF_MAIN_FORM_HSPLIT);
end;

function TAHMDesignerPrefsManager.WriteFormState(State: TAHMFormState): String;
var
  Position: TAHMFormPosition;
  sTop, sLeft, sWidth, sHeight, sMaxd: String;
begin
  if FSaveFormPos and State.Saved then Position := State.CurrentPosition
                                  else Position := State.PreviousPosition;

  // Build attribute string from either current or original form state
  sTop := ATTR_TOP + ATB + IntToStr(Position.Top) + ATN;
  sLeft := ATTR_LEFT + ATB + IntToStr(Position.Left) + ATN;
  sWidth := ATTR_WIDTH + ATB + IntToStr(Position.Width) + ATN;
  sHeight := ATTR_HEIGHT + ATB + IntToStr(Position.Height) + ATN;
  sMaxd := ATTR_MAXIMIZED + ATB + Bool2Str(Position.Maximized) + ATQ;
  Result := SPC + sTop + sLeft + sWidth + sHeight + sMaxd;
end;

function TAHMDesignerPrefsManager.WriteMainFormState(State: TAHMFormState): String;
var
  Prop: TAHMFormProperty;
  sVert, sHorz: String;
begin
  // Build standard form attributes
  Result := WriteFormState(State);

  // Build attribute string from either current or original form state
  Prop := State.GetProperty('pnLeftPanel', 'Width');
  if FSaveFormPos and State.Saved then sVert := IntToStr(Prop.CurrentValue)
                                  else sVert := IntToStr(Prop.PreviousValue);

  if FHorizLayout then Prop := State.GetProperty('pnDescriptorList', 'Width')
                  else Prop := State.GetProperty('pnDescriptorList', 'Height');
  if FSaveFormPos and State.Saved then sHorz := IntToStr(Prop.CurrentValue)
                                  else sHorz := IntToStr(Prop.PreviousValue);

  Result := Result + SPC + ATTR_VSPLIT + ATB + sVert + ATN +
                           ATTR_HSPLIT + ATB + sHorz + ATQ;
end;

function TAHMDesignerPrefsManager.ParseXML(const Filepath: String): Boolean;
var
  RootNode, NextNode: TAHMXMLNode;
begin
  // Default result - problem loading Preferences file
  Result := False;

  // Don't bother trying to parse XML file if its missing
  if not FileExists(FilePath + PREFS_FILENAME) then Exit;

  FHelper := TAHMXMLHelper.Create(Filepath + PREFS_FILENAME);
  try
    // Ignore preamble - we're looking for a DesignerPreferences node
    if not FHelper.FindRootElement(RootNode, TAG_DESIGNER_PREFS) then
      LogParsingError(XML_PRS_DPRF_MISSING_PREFS_START_TAG);

    // What nodes do we have here?
    NextNode := nil;
    while FHelper.NextElement(RootNode, NextNode) do
    begin
      if FHelper.CurrentElement = TAG_WINDOWS_SAVER then
        FWindowsSaver := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_MEDIATE_SAVER then
        FMediateSaver := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_LG_MAIN_TB then
        FLargeMainToolbar := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_LG_PREVIEW_TB then
        FLargePreviewToolbar := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_THEME_NAME then
        FThemeName := FHelper.GetValue
      else if FHelper.CurrentElement = TAG_SAVE_FORM_STATE then
        FSaveFormPos := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_PREVENT_STRETCH then
        FPreventStretch := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_HORIZONTAL_LAYOUT then
        FHorizLayout := Str2Bool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_MAIN_FORM_STATE then
        ReadMainFormState(FMainFormState)
      else
        LogWarn(XML_PRS_DPRF_FOUND_UNKNOWN_CONTENT_TAG);
    end;

    // All is well, parsed preferences file successfully
    Result := True;
  finally
    FHelper.Free;
  end;
end;

procedure TAHMDesignerPrefsManager.SaveAsXML(Lines: TStrings);
begin
  Lines.Add(XML_PREAMBLE);
  Lines.Add(BeginTag(TAG_DESIGNER_PREFS));

  Lines.Add(TABS[1] + BeginTag(TAG_WINDOWS_SAVER) + Bool2Str(FWindowsSaver) + EndTag(TAG_WINDOWS_SAVER));
  Lines.Add(TABS[1] + BeginTag(TAG_MEDIATE_SAVER) + Bool2Str(FMediateSaver) + EndTag(TAG_MEDIATE_SAVER));
  Lines.Add(TABS[1] + BeginTag(TAG_LG_MAIN_TB) + Bool2Str(FLargeMainToolbar) + EndTag(TAG_LG_MAIN_TB));
  Lines.Add(TABS[1] + BeginTag(TAG_LG_PREVIEW_TB) + Bool2Str(FLargePreviewToolbar) + EndTag(TAG_LG_PREVIEW_TB));
  Lines.Add(TABS[1] + BeginTag(TAG_PREVENT_STRETCH) + Bool2Str(FPreventStretch) + EndTag(TAG_PREVENT_STRETCH));
  Lines.Add(TABS[1] + BeginTag(TAG_HORIZONTAL_LAYOUT) + Bool2Str(FHorizLayout) + EndTag(TAG_HORIZONTAL_LAYOUT));
  Lines.Add(TABS[1] + BeginTag(TAG_THEME_NAME) + FThemeName + EndTag(TAG_THEME_NAME));
  Lines.Add(TABS[1] + BeginTag(TAG_SAVE_FORM_STATE) + Bool2Str(FSaveFormPos) + EndTag(TAG_SAVE_FORM_STATE));
  Lines.Add(TABS[1] + TGB+TAG_MAIN_FORM_STATE + WriteMainFormState(FMainFormState) + ETE);

  Lines.Add(EndTag(TAG_DESIGNER_PREFS));
end;

procedure TAHMDesignerPrefsManager.LogParsingError(const sErrorCode: String);
begin
  // Raise exception for global error handler...
  raise EConfigurationException.Create('Encountered error whilst parsing Designer Preferences XML: ' + sErrorCode);
end;

end.
